using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Windows.Threading;

namespace Chaos.network
{
    public class connection
    {
        protected Thread m_thread;
        protected String m_user;
        protected IPEndPoint m_ipendpoint;

        public String User
        {
            get { return m_user; }
            set { m_user = value; }
        }

        public IPEndPoint IPEndPoint
        {
            get { return m_ipendpoint; }
            set { m_ipendpoint = value; }
        }

        public enum estate
        {
            kState_ReadHeader,
            kState_ReadPacket
        };

        public virtual void start()
        {
            if (OnNetworkConnected != null)
            {
                OnNetworkConnected(this, new OnNetworkConnectedEvent());
            }
        }

        public virtual void abort()
        {
            if (OnNetworkDisConnected != null)
            {
                OnNetworkDisConnected(this, new OnNetworkDisConnectedEvent());
            }
        }

        public virtual void senddata(IPEndPoint to, byte[] buffer, int bufflen)
        {           
        }

        public static byte[] messagetobytes(messages.message message)
        {
            MemoryStream ms = new MemoryStream();
            ms.Write(BitConverter.GetBytes(1), 0, 4);
            stream.ostream_xml s = new stream.ostream_xml();
            s.open(ms);
            message.serialize(s);
            s.close();
            byte[] bytes = ms.ToArray();
            byte[] length = BitConverter.GetBytes(bytes.Length);
            System.Array.Copy(length, bytes, length.Length);
            ms.Close();
            return bytes;
        }

        public static messages.message bytestomessage(byte[] buffer, int bufflen)
        {
            MemoryStream ms = new MemoryStream(buffer, 0, bufflen);
            messages.factory f = new messages.factory();
            stream.istream_xml s = new stream.istream_xml(f);
            messages.packet packet = new messages.packet();
            s.open(ms);
            packet.serialize(s);
            s.close();
            ms.Close();
            return packet;
        }

        public virtual void recievedata(IPEndPoint from, byte[] buffer, int bufflen)
        {
            try
            {
                messages.packet packet = bytestomessage(buffer, bufflen) as messages.packet;
                recievemessage(from, packet.Data as messages.message);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
            }
        }

        public void recievemessage(IPEndPoint in_ipendpoint, messages.message message)
        {
            if (OnNetworkData != null)
            {
                OnNetworkData(this, new OnNetworkDataEvent(in_ipendpoint, message));
            }
        }

        public void sendmessage(messages.message message)
        {
            messages.packet packet = new messages.packet();
            packet.Data = message;
            byte[] bytes = messagetobytes(packet);
            senddata(m_ipendpoint, bytes, bytes.Length);
        }

        public void sendmessage(IPEndPoint in_ipendpoint, messages.message message)
        {
            messages.packet packet = new messages.packet();
            packet.Data = message;
            byte[] bytes = messagetobytes(packet);
            senddata(in_ipendpoint, bytes, bytes.Length);
        }
                
        public class OnNetworkDataEvent : EventArgs
        {
            public OnNetworkDataEvent(IPEndPoint in_ipendpoint, messages.message in_message)
            {
                Message = in_message;
                IPEndPoint = in_ipendpoint;
            }

            public messages.message Message
            {
                get;
                set;
            }
            public IPEndPoint IPEndPoint
            {
                get;
                set;
            }
        };


        public class OnNetworkConnectedEvent : EventArgs
        {
            public OnNetworkConnectedEvent()
            {
            }
        };

        public class OnNetworkDisConnectedEvent : EventArgs
        {
            public OnNetworkDisConnectedEvent()
            {
            }
        };

        public delegate void OnNetworkDataDelegate(object sender, OnNetworkDataEvent e);
        public delegate void OnNetworkConnectedDelegate(object sender, OnNetworkConnectedEvent e);
        public delegate void OnNetworkDisConnectedDelegate(object sender, OnNetworkDisConnectedEvent e);

        public event OnNetworkDataDelegate OnNetworkData;
        public event OnNetworkConnectedDelegate OnNetworkConnected;
        public event OnNetworkDisConnectedDelegate OnNetworkDisConnected;


        public class messagebuffer
        {
            public byte[] Buffer { get; set; }
            public int ToRead { get; set; }
            public int Read { get; set; }
            public connection.estate State { get; set; }
        }

    }
}
